package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.api.dto.leanring.LearningRecordDTO;
import com.tianji.api.dto.trade.OrderBasicDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.domain.query.PageQuery;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.status.LessonStatus;
import com.tianji.common.status.PlanStatus;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.ObjectUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.entity.LearningLesson;
import com.tianji.learning.mapper.LearningLessonMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.learning.vo.LearningLessonVO;
import com.tianji.learning.vo.LearningPlanPageVO;
import com.tianji.learning.vo.LearningPlanVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 学生课程表 服务实现类
 * </p>
 *
 * @author author
 * @since 2023-05-25
 */
@Service
@Slf4j
public class LearningLessonServiceImpl extends ServiceImpl<LearningLessonMapper, LearningLesson> implements ILearningLessonService {

    @Autowired
    private CourseClient courseClient;
    @Autowired
    private CatalogueClient catalogueClient;
    /**
     * 下单回调添加课程方法
     */
    @Override
    public void listenLessonPay(Long userId, List<Long> courseIds) {
        // 1.查询课程有效期
        List<CourseSimpleInfoDTO> cInfoList = courseClient.getSimpleInfoList(courseIds);
        if (CollUtils.isEmpty(cInfoList)) {
            // 课程不存在，无法添加
            log.error("课程信息不存在，无法添加到课表");
            return;
        }
        //1.2 安全校验
        if (cInfoList.size() != courseIds.size()){
            log.error("课程id列表为：{}，查询到的课程数：{}",courseIds,cInfoList.size());
            throw new BadRequestException("课程id存在问题，请维护人员自行检查");
        }
        // 2.循环遍历，处理LearningLesson数据
        List<LearningLesson> list = new ArrayList<>(cInfoList.size());
        for (CourseSimpleInfoDTO cInfo : cInfoList) {
            LearningLesson lesson = new LearningLesson();
            // 2.1.获取过期时间
            Integer validDuration = cInfo.getValidDuration();
            if (validDuration != null && validDuration > 0) {
                LocalDateTime now = LocalDateTime.now();
                lesson.setCreateTime(now);
                lesson.setExpireTime(now.plusMonths(validDuration));
            }
            // 2.2.填充userId和courseId
            lesson.setUserId(userId);
            lesson.setCourseId(cInfo.getId());
            list.add(lesson);
        }
        // 3.批量新增
        saveBatch(list);
    }

    /**
     * 分页查询
     *
     * @param query
     * @return
     */
    @Override
    public PageDTO<LearningLessonVO> queryMyLessons(PageQuery query) {
        //1、获取用户信息
        Long userId = UserContext.getUser();
        //2、根据条件发起分页查询
        Page<LearningLesson> page = this.lambdaQuery().eq(LearningLesson::getUserId, userId)
                .page(query.toMpPage("latest_learn_time", false));
        List<LearningLesson> records = page.getRecords();
        //2.1、为空直接返回
        if(ObjectUtils.isEmpty(records))return PageDTO.empty(page);

        //3、根据ids查询课程信息
        List<Long> ids = records.stream().map(LearningLesson::getCourseId).collect(Collectors.toList());
        List<CourseSimpleInfoDTO> cInfoList = courseClient.getSimpleInfoList(ids);
        //3.2、转为Map
        Map<Long, CourseSimpleInfoDTO> cMap = cInfoList.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));
        //4、将课程信息封装到VO中返回
        List<LearningLessonVO> list = new ArrayList<>();
        for (LearningLesson record : records) {
            LearningLessonVO vo = BeanUtils.copyBean(record, LearningLessonVO.class);
            //4.2、属性填充
            CourseSimpleInfoDTO cInfo = cMap.get(record.getCourseId());
            vo.setCourseName(cInfo.getName());
            vo.setCourseCoverUrl(cInfo.getCoverUrl());
            vo.setSections(cInfo.getSectionNum());
            list.add(vo);
        }
        return PageDTO.of(page, list);
    }

    /**
     * 查询我的最近学习的课程
     * @return
     */
    @Override
    public LearningLessonVO getInfo() {
        //1、获取登录用户id
        Long userId = UserContext.getUser();
        //2、条件查询
        LearningLesson lesson = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getStatus, LessonStatus.LEARNING.getValue())
                .orderByDesc(LearningLesson::getLatestLearnTime)
                .last("limit 1")
                .one();

        if (lesson == null) return null;

        // 3.拷贝PO基础属性到VO
        LearningLessonVO vo = BeanUtils.copyBean(lesson, LearningLessonVO.class);

        // 4.查询课程信息
        CourseFullInfoDTO cInfo = courseClient.getCourseInfoById(lesson.getCourseId(), false, false);
        if (cInfo == null) {
            throw new BadRequestException("课程不存在");
        }
        vo.setCourseName(cInfo.getName());
        vo.setCourseCoverUrl(cInfo.getCoverUrl());
        vo.setSections(cInfo.getSectionNum());
        // 5.统计课表中的课程数量 select count(1) from xxx where user_id = #{userId}
        Integer courseAmount = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .count();
        vo.setCourseAmount(courseAmount);
        // 6.查询小节信息
        List<CataSimpleInfoDTO> cataInfos =
                catalogueClient.batchQueryCatalogue(CollUtils.singletonList(lesson.getLatestSectionId()));
        if (!CollUtils.isEmpty(cataInfos)) {
            CataSimpleInfoDTO cataInfo = cataInfos.get(0);
            vo.setLatestSectionName(cataInfo.getName());
            vo.setLatestSectionIndex(cataInfo.getCIndex());
        }
        return vo;
    }

    /**
     * 检验用户是否有播放视频的资格
     *
     * @param courseId
     * @return
     */
    @Override
    public Long isLessonValid(Long courseId) {
        //1、获取用户信息
        Long userId = UserContext.getUser();
        //2、根据条件发起分页查询
        LearningLesson learning = this.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId)
                .one();
        //3、判断
        if (ObjectUtils.isEmpty(learning))  return null;
        if (learning.getStatus().equals(LessonStatus.EXPIRED)) return null;
        //4、获取课表id
        CourseFullInfoDTO cInfo = courseClient.getCourseInfoById(learning.getCourseId(), false, false);
        if (cInfo == null) return null;
        return cInfo.getId();
    }

    /**
     * 查询用户是否有该课程
     *
     * @param courseId
     * @return
     */
    @Override
    public LearningLesson getAuthority(Long courseId) {
        //1、获取用户id
        Long userId = UserContext.getUser();
        //2、查询课程信息
        LearningLesson learningLesson = this.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId)
                .one();
        //3、判断
        if (learningLesson != null){
            return learningLesson;
        }
        return new LearningLesson();
    }

    /**
     * 查询课程学习人数
     *
     * @param courseId
     * @return
     */
    @Override
    public Integer countLearningLessonByCourse(Long courseId) {
        return this.lambdaQuery()
                .eq(LearningLesson::getCourseId, courseId)
                .count();
    }

    /**
     * 创建学习计划
     *
     * @param courseId
     * @param freq
     */
    @Override
    public void createLearningPlan(Long courseId, Integer freq) {
        //1.获取当前登录用户id
        Long userId = UserContext.getUser();
        this.lambdaUpdate()
                .set(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING)
                .set(LearningLesson::getWeekFreq,freq)
                .eq(LearningLesson::getCourseId,courseId)
                .eq(LearningLesson::getUserId,userId)
                .update();
    }

    /**
     * 查询我的学习计划
     *
     * @param query
     * @return
     */
    @Override
    @Transactional
    public LearningPlanPageVO queryMyPlans(PageQuery query) {
        //1.获取当前登录用户
        Long userId = UserContext.getUser();
        //2.查询本周计划数与总计划学习数量
        Integer weekFinished =  this.baseMapper.selectWeekFinished(userId,null);
        Integer weekTotalPlan =  this.baseMapper.selectWeekTotalPlan(userId,null);
        //TODO 2.1 积分值
        LearningPlanPageVO vo = LearningPlanPageVO.builder()
                .weekFinished(weekFinished)
                .weekTotalPlan(weekTotalPlan)
                .weekPoints(0)
                .build();
        //3.封装Page查询对象
        //3.1 用户课表

        Page<LearningLesson> page = this.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING)
                .in(LearningLesson::getStatus, LessonStatus.NOT_BEGIN, LessonStatus.LEARNING)
                .page(query.toMpPage("latest_learn_time", false));
        List<LearningLesson> lessonList = page.getRecords();

        List<Long> ids = lessonList.stream().map(LearningLesson::getCourseId).collect(Collectors.toList());
        //3.2 查询课程信息集合
        Map<Long, CourseSimpleInfoDTO> cMap = this.courseClient.getSimpleInfoList(ids)
                .stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));

        List<LearningPlanVO> pageVoList = new ArrayList<>();
        for (LearningLesson lesson : lessonList) {
            //课程信息实体
            CourseSimpleInfoDTO csdto = cMap.get(lesson.getCourseId());
            //3.3 课程计划信息对象
            LearningPlanVO pageVo = LearningPlanVO.builder()
                    .id(lesson.getId())
                    .courseId(lesson.getCourseId())
                    .courseName(csdto.getName())
                    .weekFreq(lesson.getWeekFreq())
                    .weekLearnedSections(lesson.getLearnedSections())
                    .sections(csdto.getSectionNum())
                    .learnedSections(lesson.getLearnedSections())
                    .latestLearnTime(lesson.getLatestLearnTime())
                    .build();
            //存入集合
            pageVoList.add(pageVo);
            vo.pageInfo(page.getTotal(),page.getPages(), pageVoList);
        }

        return vo;
    }
}
